package sis.search;/*
 * @auther 顶风少年
 * @mail dfsn19970313@foxmail.com
 * @date 2019-08-01 14:36
 * @notify
 * @version 1.0
 */

import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Server extends Thread {
    //搜索器集合
    private BlockingQueue<Search> queue = new LinkedBlockingQueue<>();
    //监听器
    private ResultsListener listener;

    public static final String START_MSG = "started";
    public static final String END_MSG = "finished";

    //创建一个 ThreadLocal 并设置默认返回值为一个空的集合
    private static ThreadLocal<List<String>> threadLog = new ThreadLocal<List<String>>() {
        protected List<String> initialValue() {
            return new ArrayList<>();
        }
    };

    //同步的 list 用来存放日志
    private List<String> completeLog = Collections.synchronizedList(new ArrayList<>());

    public List<String> getLog() {
        return completeLog;
    }

    //初始化一个监听器
    public Server(ResultsListener listener) {
        this.listener = listener;
        //启动 run方法 从 服务器启动就一直开始 准备搜索.
        start();
    }

    //不停的搜索
    public void run() {
        //循环搜索
        while (true) {
            try {
                //此方法会进行阻塞,如果没有元素出栈,则阻塞
                execute(queue.take());
            } catch (InterruptedException e) {
                break;
            }
            //让出线程执行权
            Thread.yield();
        }
    }

    //中断线程,会抛出异常
    public void shutDown() throws Exception {
        this.interrupt();
    }

    //添加搜索
    public void add(Search search) throws Exception {
        queue.put(search);
    }

    //执行
    private void execute(Search search) {
        //每一次执行回调都创建一个线程,由新线程执行回调
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                log(START_MSG, search);
                //执行搜索
                search.execute();
                //编辑日志
                log(END_MSG, search);
                //增加搜索次数
                listener.executed(search);
                //添加日志
                completeLog.addAll(threadLog.get());
            }
        });
        //用来捕获run方法中的异常
        thread.setUncaughtExceptionHandler(
                new Thread.UncaughtExceptionHandler() {
                    public void uncaughtException(Thread th, Throwable thrown) {
                        completeLog.add(search + " " + thrown.getMessage());
                    }
                }
        );
        thread.start();
    }

    //编辑日志
    private void log(String message, Search search) {
        //拿到当前线程的日志对象,并添加新的记录
        threadLog.get().add(search + " " + message + " at " + new Date());
    }
}

